package com.example.adminbase.mybatisgenerator;

import com.github.javaparser.JavaParser;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.ImportDeclaration;
import com.github.javaparser.ast.NodeList;
import com.github.javaparser.ast.body.BodyDeclaration;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.TypeDeclaration;
import com.github.javaparser.ast.comments.Comment;
import org.mybatis.generator.exception.ShellException;
import org.mybatis.generator.internal.DefaultShellCallback;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Optional;

public class JavaMergeShellCallback extends DefaultShellCallback {
    /**
     * Instantiates a new default shell callback.
     *
     * @param overwrite the overwrite
     */
    public JavaMergeShellCallback(boolean overwrite) {
        super(overwrite);
    }

    @Override
    public boolean isMergeSupported() {
        return true;
    }

    @Override
    public String mergeJavaFile(String newFileSource, File existingFile, String[] javadocTags, String fileEncoding) throws ShellException {
        /**
        *    Delete any methods/fields in the existing file that have the specified JavaDoc tag
        *    Make sure that the existing file is of the same type as the existing file (either interface or class)
        *    Add any new imports from the new file into the existing file
        *    Add all methods and fields from the new file into the existing file
        *    Format the resulting source string
        * */

        CompilationUnit sourceUnit = JavaParser.parse(newFileSource), existingUnit;
        try {
            existingUnit = JavaParser.parse(existingFile);
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        }
        // TODO: 2018/9/19 0019 合并import

        //合并成员
        ClassOrInterfaceDeclaration sourceTypeDeclaration = (ClassOrInterfaceDeclaration) sourceUnit.getType(0);
        ClassOrInterfaceDeclaration existingTypeDeclaration = (ClassOrInterfaceDeclaration) existingUnit.getType(0);
        NodeList<BodyDeclaration<?>> resultMembers = mergeMembers(sourceTypeDeclaration.getMembers(), existingTypeDeclaration.getMembers(), javadocTags);
        existingTypeDeclaration.setMembers(resultMembers);

        //覆盖existingUnit的继承关系，实现的接口
        existingTypeDeclaration.setExtendedTypes(sourceTypeDeclaration.getExtendedTypes());
        existingTypeDeclaration.setImplementedTypes(sourceTypeDeclaration.getImplementedTypes());

        return existingUnit.toString();
    }

    private NodeList<BodyDeclaration<?>> mergeMembers(NodeList<BodyDeclaration<?>> sourceMembers, NodeList<BodyDeclaration<?>> existingMembers, String[] javadocTags) {
        NodeList<BodyDeclaration<?>> resultMembers = new NodeList<>(sourceMembers);
        for (BodyDeclaration<?> member : existingMembers) {
            Optional<Comment> optionalComment = member.getComment();
            if(optionalComment.isPresent()) {
                Comment comment = optionalComment.get();

                boolean contain = false;
                for(String javadocTag : javadocTags) {
                    if(comment.getContent().contains(javadocTag)) {
                        contain = true;
                        break;
                    }
                }
                if(!contain) {
                    resultMembers.add(member);
                }
            }else {
                resultMembers.add(member);
            }

        }
        return resultMembers;
    }
}
